using System;
using System.Collections.Generic;
using System.Text;

namespace SteeringBehaviors
{
    public class Team
    {
        #region PRIVATE MEMBERS

        Microsoft.DirectX.Direct3D.ColorValue teamColor;
        List<TaskForce> taskForces;

        #endregion

        #region PROPERTIES

        /// <summary>
        /// Gets the Carrier Defense Force of this team.
        /// </summary>
        /// <remarks>This may return null if no task forces are present for this team.</remarks>
        public CarrierDefenseForce CDF
        {
            get
            {
                if (taskForces.Count != 0)
                    return (CarrierDefenseForce)taskForces[0];
                return null;
            }
        }

        /// <summary>
        /// Gets the list of all contained taskforces of this Team
        /// </summary>
        public List<TaskForce> TaskForces
        {
            get { return taskForces; }
        }

        #endregion

        #region CONSTRUCTORS

        /// <summary>
        /// Default constructor
        /// </summary>
        public Team()
        {
            teamColor = new Microsoft.DirectX.Direct3D.ColorValue(1f, 1f, 1f, 1f);
            taskForces = new List<TaskForce>();
            // each team always has at least one taskforce with a carrier
            taskForces.Add(new CarrierDefenseForce());
        }

        #endregion

        #region INTERFACE METHODS

        /// <summary>
        /// Removes all taskforces with zero ships
        /// </summary>
        public void PruneTaskForces()
        {
            for (int i = 0; i < taskForces.Count; ++i)
            {
                if (taskForces[i].Ships.Count == 0)
                {
                    taskForces.RemoveAt(i);
                    --i;
                }
            }
        }

        /// <summary>
        /// Disband a task force of this team
        /// </summary>
        /// <param name="index">index of the task force to disband</param>
        /// <remarks>The CarrierDefenseForce (CDF) can not be disbanded.</remarks>
        public void DisbandTaskForce(int index)
        {
            if (index < taskForces.Count && index != 0)
            {
                List<Ship> disbandedShips = taskForces[index].Disband();
                taskForces.RemoveAt(index);
                if (index != 0)
                    for (int i = 0; i < disbandedShips.Count; ++i)
                        CDF.AddShip(disbandedShips[i]);
            }
        }

        /// <summary>
        /// Disband a ship from a specified task force
        /// </summary>
        /// <param name="taskForceIndex">the index of the specified task force</param>
        /// <param name="shipID">the ID of the ship to disband from the specified task force</param>
        /// <remarks>ships disbanded from the CarrierDefenseForce (a.k.a. CDF) will be scrapped and removed from the game</remarks>
        public void DisbandShipInTaskForce(int taskForceIndex, uint shipID)
        {
            if (taskForceIndex < taskForces.Count)
            {
                if (taskForceIndex != 0)
                {
                    Ship shipToDisband = taskForces[taskForceIndex].DisbandShip(shipID);
                    if (shipToDisband != null)
                        CDF.AddShip(shipToDisband);
                }
                else
                    taskForces[0].DisbandShip(shipID);
            }
        }

        /// <summary>
        /// Gets the number of ships of a specified type on this team.
        /// </summary>
        /// <param name="shipType">The name of the specified type</param>
        /// <returns>the number of ships of a specified type on this team</returns>
        public int GetNumberOfShipType(string shipType)
        {
            int total = 0;
            for (int i = 0; i < taskForces.Count; ++i)
                total += taskForces[i].GetNumberOfShipType(shipType);
            return total;
        }

        /// <summary>
        /// Perform bounds checking on all task forces of this
        /// team usings the provided bounds
        /// </summary>
        /// <param name="bounds">a vector representing the size of the bound area</param>
        public void BoundsCheck(Microsoft.DirectX.Vector3 bounds)
        {
            for (int i = 0; i < taskForces.Count; ++i)
                taskForces[i].BoundsCheck(bounds);
        }

        /// <summary>
        /// Updates all task forces of this team
        /// </summary>
        /// <param name="delta">change in time since last update call (in seconds)</param>
        public void Update(float delta)
        {
            for (int i = 0; i < taskForces.Count; ++i)
                taskForces[i].Update(delta);
        }

        /// <summary>
        /// Render all task forces of this team
        /// </summary>
        /// <param name="sprite">DirectX sprite object that will be used when rendering</param>
        public void Render(Microsoft.DirectX.Direct3D.Sprite sprite)
        {
            for (int i = 0; i < taskForces.Count; ++i)
                taskForces[i].Render(sprite);
        }

        #endregion

        #region HELPER METHODS

        /// <summary>
        /// Creates and adds a task force based on algorithm strength provided
        /// </summary>
        /// <param name="rand">random number generator</param>
        /// <param name="alignment">alignment strength for the added task force</param>
        /// <param name="cohesion">cohesion strength for the added task force</param>
        /// <param name="separation">separation strength for the added task force</param>
        private void AddTaskForce(Random rand, float alignment, float cohesion, float separation)
        {
            Microsoft.DirectX.Direct3D.ColorValue color;
            if (alignment == 1f && cohesion == 1f &&separation == 1f)
                color = new Microsoft.DirectX.Direct3D.ColorValue(1f, 0f, 0f, 1f);
            else
                color = new Microsoft.DirectX.Direct3D.ColorValue(alignment, cohesion, separation, 1f);
            TaskForce taskForce = new TaskForce();
            taskForce.Color = color;
            for (int i = 0; i < 15; ++i)
            {
                Ship addThis;
                switch (rand.Next(3))
                {
                    case 0:
                        addThis = new Fighter();
                        break;
                    case 1:
                        addThis = new Scout();
                        break;
                    default:
                        addThis = new Worker();
                        break;
                };
                addThis.Position = new Microsoft.DirectX.Vector3(Convert.ToSingle(rand.NextDouble()) * 1600f,
                    Convert.ToSingle(rand.NextDouble()) * 1200f, 0);
                addThis.Velocity = new Microsoft.DirectX.Vector3(Convert.ToSingle(rand.NextDouble() - .5) * addThis.MaxSpeed, Convert.ToSingle(rand.NextDouble() - .5) * addThis.MaxSpeed, 0);
                taskForce.AddShip(addThis);
            }
            taskForce.AlignmentStrength = alignment;
            taskForce.CohesionStrength = cohesion;
            taskForce.SeparationStrength = separation;
            taskForces.Add(taskForce);
        }

        #endregion

    }
}
